﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows;
using System.IO;
using System.Diagnostics;
using Image2ASCII.Properties;
using System.Drawing.Imaging;

namespace Image2ASCII
{
    class Program
    {
        static Dictionary<string, string> options = new Dictionary<string, string>();

        static Dictionary<string, bool> acceptedParams = new Dictionary<string, bool>()
        {
            {"-i", false},
            {"-s", true},
            {"-r", true},
            {"-p", false}
        };

        static string input, output;
        static void Main(string[] args)
        {
            Console.WriteLine("Image2ASCII: by Adam \"Ruci00\" Rutkowski\nAll bugs please report to: adirucio96@gmail.com\n");
            if (args.Length == 0)
            {
                Console.WriteLine(Resources.help);
            }
            else
            {
                #region Argument Checking
                for (int i = 0; i < args.Length; i++)
                {
                    var arg = args[i].Trim();
                    if (options.Keys.Contains(arg))
                    {
                        Console.WriteLine("ERROR: parameter '{0}' is used more than once", arg);
                        return;
                    }
                    if (!string.IsNullOrWhiteSpace(arg))
                    {
                        if (arg[0] == '-')
                        {
                            if (i > 0 && args[i - 1][0] == '-' && acceptedParams[args[i - 1]])
                            {
                                Console.WriteLine("ERROR: no value specified for parameter '{0}'", args[i - 1]);
                                return;
                            }
                            if (acceptedParams.ContainsKey(arg))
                                options.Add(arg, string.Empty);
                            else
                            {
                                Console.WriteLine("ERROR: unknown parameter '{0}'", arg);
                                return;
                            }
                        }
                        else
                        {
                            if (i > 0 && args[i - 1][0] == '-' && acceptedParams[args[i - 1]])
                            {
                                options[args[i - 1]] = arg;
                            }
                            else
                            {
                                if (string.IsNullOrEmpty(input))
                                {
                                    if (File.Exists(arg))
                                    {
                                        input = arg;
                                    }
                                    else
                                    {
                                        Console.WriteLine("ERROR: bad path or filename");
                                        return;
                                    }
                                }
                                else
                                {
                                    output = arg;
                                }
                            }
                        }
                    }
                }
                #endregion
                if (!string.IsNullOrEmpty(input))
                {
                    if (string.IsNullOrEmpty(output))
                    {
                        output = Path.ChangeExtension(input, "txt");
                    }
                    Convert();
                }
                else
                {
                    Console.WriteLine("ERROR: no input specified!");
                    return;
                }
            }
        }


        internal static void Convert()
        {
            Stopwatch timer = new Stopwatch();
            timer.Start();
            Bitmap image = (Bitmap)Bitmap.FromFile(input);

            int outWidth = image.Width;
            int outHeight = image.Height;

            bool invert = false;
            if (options.ContainsKey("-i"))
            {
                invert = true;
            }

            if (options.ContainsKey("-p"))
            {
                Bitmap cmdImage;
                if (image.Width >= 80)
                {
                    int height = (int)(79 / ((float)image.Width / (float)image.Height));
                    cmdImage = new Bitmap(image, 79, height);
                }
                else
                {
                    cmdImage = image;
                }
                Console.WriteLine(ToASCII(cmdImage, invert));
                Console.WriteLine();
                return;
            }
            else if (options.ContainsKey("-r"))
            {
                if (options.ContainsKey("-s"))
                {
                    Console.WriteLine("ERROR: can't use '-r' and '-s' params simultaneously");
                    return;
                }
                var res = options["-r"].Split('x');

                if (res.Length == 2 && !int.TryParse(res[0], out outWidth) & !int.TryParse(res[1], out outHeight))
                {
                    Console.WriteLine("ERROR: bad resolution format");
                    return;
                }
            }
            else if (options.ContainsKey("-s"))
            {
                float scale;

                if (!float.TryParse(options["-s"], out scale))
                {
                    Console.WriteLine("ERROR: bad scale factor format");
                    return;
                }

                outWidth = (int)(outWidth * scale);
                outHeight = (int)(outHeight * scale);
            }

            Console.WriteLine("Converting image {0} to {1}, chars {2}x{3} ...\n", Path.GetFileName(input), output, outWidth, outHeight);

            if (outWidth != image.Width || outHeight != image.Height)
            {
                image = new Bitmap(image, new Size(outWidth, outHeight));
            }

            string asciiArt = ToASCII(image, invert);

            using (StreamWriter sw = File.CreateText(output))
            {
                sw.Write(asciiArt);
                sw.Flush();
            }
            timer.Stop();
            Console.WriteLine("Saved to {0} in {1}s", output, timer.Elapsed.TotalSeconds);
        }

        internal static string ToASCII(Bitmap image, bool invert = false)
        {
            string asciiArt = string.Empty;

            for (int y = 0; y < image.Height; y++)
            {
                for (int x = 0; x < image.Width; x++)
                {
                    var pixel = image.GetPixel(x, y);
                    float brightness = pixel.GetBrightness();
                    pixel.GetHue()
                    if (invert)
                    {
                        brightness = 1.0F - brightness;
                    }

                    asciiArt += CharStyles.GetGrayShade(brightness);
                }
                asciiArt += Environment.NewLine;
            }

            return asciiArt;
        }

        struct Pixel
        {
            public int TotalRGB { get { return r + g + b; } }

            public int r;
            public int g;
            public int b;
            public Pixel(int r, int g, int b)
            {
                this.r = r;
                this.g = g;
                this.b = b;
            }
        }
    }

}
